package com.zyl.dbStore;

import com.zyl.backup.BackUp;
import com.zyl.bean.Environment;
import com.zyl.factory.FactoryInstance;
import com.zyl.log.Log;
import com.zyl.log.LogImpl;
import com.zyl.utils.JdbcUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * @version v1.0
 * @ProjectName: env_gather
 * @Package: com.zyl.dbStore
 * @ClassName: DbStoreImpl
 * @Description TODO(入库模块的实现类)
 * 在入库时，需要注意将数据存入对应的表中
 * @Author 翟玉龙
 * @Date 2024/10/22-9:47
 */
public class DbStoreImpl implements DbStore {
    // 备份模块的实现类对象
    private final BackUp backup = FactoryInstance.init().getInstance("backup", BackUp.class);
    //private final BackUp backup = new BackUpImpl();
    private static final String backUpFile = "backup/dbStore.backup";
    // 日志模块的实现类对象
    private final Log log = LogImpl.getInstance();

    @Override
    public void dbStore(List<Environment> data) {
        try(Connection conn = JdbcUtil.getConnection()) {
            // 获取开始时间
            long start = System.currentTimeMillis();
            // 获取连接对象
            //Connection conn = JdbcUtil.getConnection();
            // 取消自动提交
            conn.setAutoCommit(false);
            log.info("准备进行入库操作, 本次入库的数据条数为：" + data.size());
            // 定义变量currentDay用于比较前后两条数据是否为同一天
            int currentDay = -1;
            // 定义变量count 用于统计当前遍历的环境对象数据 用于分批提交
            int count = 0;
            int commitCount = 0;
            PreparedStatement ps = null;
            try {
                // 遍历环境数据集合
                for(Environment env : data) {
                    LocalDateTime dateTime = env.getGatherDate().toLocalDateTime();
                    int day = dateTime.getDayOfMonth();
                    if(currentDay != day) {
                        // 在切换ps时，注意需要将前一批未及时提交的数据进行统一提交
                        if(ps != null && count % 500 != 0) {
                            ps.executeBatch();
                            log.debug("当前已经入库的数量为：" + commitCount);
                        }

                        // 如果currentDay与day不相等，则表明本条数据与前一批数据不是同一天
                        // 需要重新获取ps对象
                        // 需要根据环境数据的采集日期，分别将数据存入对应的表中
                        String sql = "insert into env_data_detail_" + day + " values(?,?,?,?,?,?,?,?,?,?)";
                        ps = conn.prepareStatement(sql);
                        // 获取完ps对象后，将批次转为本条数据的批次
                        currentDay = day;
                    }

                    // 模拟异常，并且将前300条数据存入数据库，将后700条数据备份
//                    if(count == 1) {
//                        int a = 10 / 0;
//                    }
                    // 赋值操作
                    initPs(Optional.ofNullable(ps).orElseThrow(() -> new RuntimeException("PreparedStatement对象为null")), env);
                    // 执行sql 每500条提交一次 或集合遍历完后也得及时提交
                    if(++count % 500 == 0 || count == data.size()) {
                        // 批量提交
                        ps.executeBatch();
                        // 提交事务
                        conn.commit();
                        // 关闭资源
                        ps.close();
                        // 当前已经提交的数据条数
                        commitCount = count;
                        log.debug("当前已经入库的数量为：" + commitCount);
                    }
//                    // 模拟异常，并且将前300条数据存入数据库，将后700条数据备份
//                    if(count == 300) {
//                        int a = 10 / 0;
//                    }
                }
                // conn.commit();
            } catch (Exception e) {
                log.error(String.format("出现异常【%s】，需要进行事务回滚，并且将数据进行备份", e.getMessage()));
                if(ps != null) {
                    ps.close();
                }
                // 整个环境数据数组是一个整体，如果出现异常，需要将剩余未提交的数据都回滚
                conn.rollback();
                // 并且将剩余未提交的数据进行备份，即跳过已经提交的数据
                // 数据处理 -> new ArrayList<>(data.subList(commitCount, data.size()))
                List<Environment> list = data.stream()
                                .skip(commitCount)
                                .toList();
                backup.store(backUpFile, list, false);
                // 将异常继续往上抛
                log.error(e.getMessage());
                throw new RuntimeException(e);
            } finally {
                conn.setAutoCommit(true);
            }
            log.info(String.format("入库成功，本次入库%s条数据",data.size()));
            log.info("结束执行入库操作");
            // 获取结束时间
            long end = System.currentTimeMillis();
            log.info(String.format("本次入库耗时：%dms",end - start));
            // 关闭资源
            JdbcUtil.close(conn, ps);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private void initPs(PreparedStatement ps, Environment env) throws Exception {
        ps.setString(1, env.getName());
        ps.setString(2, env.getSrcId());
        ps.setString(3, env.getDesId());
        ps.setString(4, env.getDevId());
        ps.setString(5, env.getSersorAddress());
        ps.setInt(6, env.getCount());
        ps.setString(7, env.getCmd());
        ps.setFloat(8, env.getData());
        ps.setInt(9, env.getStatus());
        ps.setTimestamp(10, env.getGatherDate());
        // 将本条语句添加到批次中
        ps.addBatch();
    }

}
